﻿#pragma once

#include "Envir.h"
#include "../MessageQueue.h"
#include "../MirDatabase/MapInfo.h"
#include "../../Shared/Data/SharedData.h"
#include "../MirDatabase/MineInfo.h"
#include "../MirObjects/NPCObject.h"
#include "../MirObjects/SpellObject.h"
#include "../MirObjects/PlayerObject.h"
#include "../MirObjects/DelayedAction.h"
#include "../MirObjects/ConquestObject.h"
#include "../MirDatabase/SafeZoneInfo.h"
#include "../MirObjects/MapObject.h"
#include "../../Shared/Enums.h"
#include "../../Shared/Packet.h"
#include "../MirDatabase/RespawnInfo.h"
#include "../MirDatabase/MonsterInfo.h"
#include <string>
#include <vector>
#include <cmath>
#include <limits>
#include <stdexcept>
#include <any>
#include "../../rectangularvectors.h"
#include "../../stringhelper.h"
#include "../../tangible_filesystem.h"

//C# TO C++ CONVERTER NOTE: Forward class declarations:
namespace Server::MirEnvir { class Cell; }
namespace Server::MirEnvir { class MapRespawn; }

using namespace Server::MirDatabase;
using namespace Server::MirObjects;
namespace S = ServerPackets;

namespace Server::MirEnvir
{
    class Map
    {
    public:
        virtual ~Map()
        {
            delete Info;
            delete tempConquest;
        }

    private:
        static Server::MirEnvir::Envir *getEnvir();

    protected:
        static Server::MessageQueue *getMessageQueue();

    public:
        MapInfo *Info;

        int Thread = 0;

        int Width = 0, Height = 0;
        std::vector<std::vector<Cell*>> Cells;
        std::vector<Point*> WalkableCells;
        std::vector<std::vector<Door*>> DoorIndex;
        std::vector<Door*> Doors = std::vector<Door*>();
        std::vector<std::vector<MineSpot*>> Mine;
        long long LightningTime = 0, FireTime = 0;
        int MonsterCount = 0;

        std::vector<NPCObject*> NPCs = std::vector<NPCObject*>();
        std::vector<SpellObject*> Spells = std::vector<SpellObject*>();
        std::vector<PlayerObject*> Players = std::vector<PlayerObject*>();
        std::vector<MapRespawn*> Respawns = std::vector<MapRespawn*>();
        std::vector<DelayedAction*> ActionList = std::vector<DelayedAction*>();

        std::vector<ConquestObject*> Conquest = std::vector<ConquestObject*>();
        ConquestObject *tempConquest;

        Map(MapInfo *info);

        Door *AddDoor(unsigned char DoorIndex, Point *location);

        bool OpenDoor(unsigned char DoorIndex);

    private:
        unsigned char FindType(std::vector<unsigned char> &input);

        void LoadMapCellsv0(std::vector<unsigned char> &fileBytes);

        void LoadMapCellsv1(std::vector<unsigned char> &fileBytes);

        void LoadMapCellsv2(std::vector<unsigned char> &fileBytes);

        void LoadMapCellsv3(std::vector<unsigned char> &fileBytes);

        void LoadMapCellsv4(std::vector<unsigned char> &fileBytes);

        void LoadMapCellsv5(std::vector<unsigned char> &fileBytes);

        void LoadMapCellsv6(std::vector<unsigned char> &fileBytes);

        void LoadMapCellsv7(std::vector<unsigned char> &fileBytes);

        void LoadMapCellsV100(std::vector<unsigned char> &Bytes);

    public:
        bool Load();

    private:
        void CreateSafeZone(SafeZoneInfo *info);

        void CreateMine();

    public:
        Cell *GetCell(Point *location);

        Cell *GetCell(int x, int y);

        bool ValidPoint(Point *location);
        bool ValidPoint(int x, int y);

        bool CheckDoorOpen(Point *location);

        void Process();

    private:
        void ProcessRespawns();

    public:
        void Process(DelayedAction *action);

    private:
        void CompleteMagic(std::vector<std::any> &data);

    public:
        void AddObject(MapObject *ob);

        void RemoveObject(MapObject *ob);


        SafeZoneInfo *GetSafeZone(Point *location);

        std::vector<SpellObject*> GetSpellObjects(Spell spell, MapObject *caster);

        ConquestObject *GetConquest(Point *location);

        //public ConquestObject GetInnerConquest(Map map, Point location)
        //{
        //    for (int i = 0; i < Conquest.Count; i++)
        //    {
        //        ConquestObject swi = Conquest[i];
        //        if (map.Info.Index != swi.Info.MapIndex) continue;

        //        if (Functions.InRange(swi.Info.KingLocation, location, swi.Info.KingSize) && swi.WarIsOn)
        //            return swi;
        //    }
        //    return null;
        //}

        void Broadcast(Packet *p, Point *location);

        void BroadcastNPC(Packet *p, Point *location);


        void Broadcast(Packet *p, Point *location, PlayerObject *Player);
    };
    class Cell
    {
    public:
        static Cell *getLowWall();
        static Cell *getHighWall();

        bool getValid() const;

        std::vector<MapObject*> Objects;
        CellAttribute Attribute = static_cast<CellAttribute>(0);
        signed char FishingAttribute = -1;

        void Add(MapObject *mapObject);
        void Remove(MapObject *mapObject);
    };
    class MapRespawn
    {
    public:
        virtual ~MapRespawn()
        {
            delete Info;
            delete Monster;
            delete Map;
        }

    protected:
        static Server::MirEnvir::Envir *getEnvir();

    public:
        RespawnInfo *Info;
        MonsterInfo *Monster;
        Map *Map;
        int Count = 0;
        long long RespawnTime = 0;
        unsigned long long NextSpawnTick = 0;
        unsigned char ErrorCount = 0;

        std::vector<RouteInfo*> Route;

        MapRespawn(RespawnInfo *info);
        bool Spawn();

        void LoadRoutes();
    };
}
